#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>

#define NUM 1024
#define OPT_NUM 64



//#define DEBUG 
char lineCommand[NUM];
char* myargv[OPT_NUM];//指针数组:用于存放你在命令行中写的命令
int lastCode = 0;//错误码
int lastSig = 0;//异常信号


int main(){
  //输出提示符
  while(1){
  printf("用户名@主机名 当前路径# ");
  fflush(stdout);

  char* s = fgets(lineCommand,sizeof(lineCommand)-1,stdin);
  assert(s!=NULL);
  (void)s;
  //清除缓冲区中，用户输入的\n
  lineCommand[strlen(lineCommand)-1] = 0;
  
  //字符串切割
  //”ls -a -l“->"ls" "-a" "-l"
  myargv[0] = strtok(lineCommand," ");//根据”“做切割
  int i=1;
  //myargv[1] = strtok(NULL," ");
  while(myargv[i++] = strtok(NULL," "));//第二次切割原生的字符串，要传NULL 
  
  //为啥我们自己写的shell，cd的时候，路径没有发生变化呢？
  //fork创建了子进程，实际上是子进程去执行的cd，更改的就是子进程的路径
  //但是子进程结束后，继续用的是父进程，即shell，所以看不到变化
  
  //如果是cd命令，我们就不创建子进程，让shell自己执行，本质就是执行系统接口
  //像这种不需要我们的子进程来执行，而是让shell自己执行的命令，就称为--内建/内置命令
  if(myargv[0] != NULL && strcmp(myargv[0],"cd") == 0){
    if(myargv[1] != NULL){
      chdir(myargv[1]);  //cd去哪个路径，那就把工作目录修改为那个路径
    }
    continue;
  }


  //echo的实现
  if(myargv[0]!=NULL && myargv[1]!=NULL && strcmp(myargv[0],"echo") == 0 ){
    if(strcmp(myargv[1],"$?") == 0){
      printf("%d,%d\n",lastCode,lastSig);
    }else{
      printf("%s\n",myargv[1]);
    }
    continue;

  }




  //测试
#ifdef DEBUG 
  for(int i=0;myargv[i];i++){
    printf("myargv[%d]:%s\n",i,myargv[i]);
  }
#endif
  pid_t id = fork();
  assert(id !=-1);
  if(id == 0){
    execvp(myargv[0],myargv);
    exit(1);
  }
  int status = 0;
  pid_t ret = waitpid(id,&status,0);
  assert(ret > 0);
  (void)ret;
  lastCode = (status>>8)&0xFF;
  lastSig = status & 0x7F;

  }
  return 0;
}


